﻿Option Strict On
Imports System.Data.OleDb
Imports System.IO
Imports ADOX
Imports Microsoft.Office.Interop
Imports OleDbConnection = System.Data.OleDb.OleDbConnection

Module AccessDbManager


#Region "DB新規作成・削除・閉じる テーブル"
    '＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
    'MyDB新規作成
    '＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
    Public Sub Db新規作成(ByVal Mydb As String)
        If String.IsNullOrWhiteSpace(Mydb) Then
            Throw New ArgumentException("Mydb に有効なパスを指定してください。", NameOf(Mydb))
        End If

        Try
            ' 既存ファイルの削除前に COM オブジェクトを強制解放
            If File.Exists(Mydb) Then
                ' 1. Access プロセスを強制終了
                Try
                    Dim accessProcesses = Process.GetProcessesByName("MSACCESS")
                    For Each proc In accessProcesses
                        Try
                            proc.Kill()
                            proc.WaitForExit(2000)
                        Catch
                        End Try
                    Next
                Catch
                End Try

                ' 2. ガベージコレクションを強制実行
                For i As Integer = 1 To 2
                    GC.Collect()
                    GC.WaitForPendingFinalizers()
                Next

                ' 3. ロックファイル (.laccdb) を削除
                Dim lockFile As String = Path.ChangeExtension(Mydb, ".laccdb")
                If File.Exists(lockFile) Then
                    Try
                        File.Delete(lockFile)
                    Catch
                        ' ロックファイルの削除失敗は無視
                    End Try
                End If

                System.Threading.Thread.Sleep(1000)

                ' 4. データベースファイル削除をリトライ
                Dim deleted As Boolean = False
                For i As Integer = 1 To 5
                    Try
                        File.Delete(Mydb)
                        deleted = True
                        Exit For
                    Catch ex As IOException
                        If i < 5 Then
                            System.Threading.Thread.Sleep(1000)
                            GC.Collect()
                            GC.WaitForPendingFinalizers()
                        Else
                            ' 最終的に失敗した場合、詳細なエラーメッセージを表示
                            Throw New IOException(
                                $"データベースファイルを削除できません。{vbCrLf}" &
                                $"パス: {Mydb}{vbCrLf}" &
                                $"以下を確認してください:{vbCrLf}" &
                                $"1. Accessアプリケーションが開いていないか{vbCrLf}" &
                                $"2. エクスプローラーでファイルを開いていないか{vbCrLf}" &
                                $"3. 他のプログラムがファイルを使用していないか{vbCrLf}" &
                                $"元のエラー: {ex.Message}", ex)
                        End If
                    End Try
                Next
            End If

            ' ADOX.Catalog のインスタンス生成
            ' ※参照設定で「Microsoft ADO Ext. x.x for DDL and Security」が必要です
            Dim cat As Object = CreateObject("ADOX.Catalog")

            Try
                Dim connStr As String = $"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={Mydb};"
                ' データベース作成
                CallByName(cat, "Create", CallType.Method, connStr)
            Finally
                ' COM オブジェクトの確実な解放
                If cat IsNot Nothing Then
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(cat)
                    cat = Nothing
                End If
            End Try

        Catch ex As Exception
            ' 呼び出し元へエラーを再送
            Throw
        End Try

    End Sub
    '＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
    ' MyDBのファイルサイズがSaizu(MB)以上であればAccessデータベースを最適化する
    '＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
    Public Sub Access最適化(MyDB As String, Saizu As Integer)
        If Not File.Exists(MyDB) Then Exit Sub

        Dim fi As New FileInfo(MyDB)
        If fi.Length < CLng(Saizu) * 1024L * 1024L Then Exit Sub

        Dim tempPath As String = MyDB & ".tmp"
        Try
            Dim compacted As Boolean = False

            ' Try JRO (Jet Replication Objects)
            Dim jro As Object = Nothing
            Try
                jro = CreateObject("JRO.JetEngine")
                Dim args As Object() = {
                    "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB,
                    "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & tempPath
                }
                jro.GetType().InvokeMember("CompactDatabase",
                    Reflection.BindingFlags.InvokeMethod,
                    Nothing, jro, args)
                compacted = True
            Catch
                ' ignore and try DAO below
            Finally
                If jro IsNot Nothing Then
                    Try
                        System.Runtime.InteropServices.Marshal.ReleaseComObject(jro)
                    Catch
                    End Try
                    jro = Nothing
                End If
            End Try

            ' Fallback: try DAO compact (if available)
            If Not compacted Then
                Try
                    Dim dbe As Object = CreateObject("DAO.DBEngine.120")
                    ' DAO.CompactDatabase requires source and destination paths
                    Dim args As Object() = {MyDB, tempPath}
                    dbe.GetType().InvokeMember("CompactDatabase",
                        Reflection.BindingFlags.InvokeMethod,
                        Nothing, dbe, args)
                    compacted = True
                    Try
                        System.Runtime.InteropServices.Marshal.ReleaseComObject(dbe)
                    Catch
                    End Try
                    dbe = Nothing
                Catch
                    ' ignore, will raise error below if not compacted
                End Try
            End If

            If Not compacted Then
                Throw New Exception("データベースの最適化に失敗しました。JRO/DAO コンポーネントが利用できないか、プロバイダのビット数が一致していない可能性があります。")
            End If

            File.Delete(MyDB)
            File.Move(tempPath, MyDB)
        Catch ex As Exception
            If File.Exists(tempPath) Then File.Delete(tempPath)
            MsgBox("Access最適化エラー: " & ex.Message)
        End Try
    End Sub

    ''' <summary>
    ''' 指定テーブルの列名を変更します。まず ADOX で列名を直接変更し、失敗した場合は
    ''' ALTER TABLE で新しい列を追加してコピー、旧列を削除するフォールバックを行います。
    ''' </summary>
    Public Sub Rename判定ToE判定()
        Dim tableName As String = "T160_全出荷E集計"
        If String.IsNullOrWhiteSpace(MyDB) Then
            MsgBox("DBパス未設定のため列名変更を中止します。")
            Return
        End If

        Dim cat As ADOX.Catalog = Nothing
        Try
            cat = New ADOX.Catalog()
            cat.let_ActiveConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")

            Dim tbl As ADOX.Table = Nothing
            For i As Integer = 0 To cat.Tables.Count - 1
                If String.Equals(cat.Tables(i).Name, tableName, StringComparison.OrdinalIgnoreCase) Then
                    tbl = cat.Tables(i)
                    Exit For
                End If
            Next

            If tbl Is Nothing Then
                MsgBox("テーブル '" & tableName & "' が見つかりません。")
                Return
            End If

            Dim hasOld As Boolean = False
            Dim hasNew As Boolean = False
            For j As Integer = 0 To tbl.Columns.Count - 1
                Dim cname As String = tbl.Columns(j).Name
                If String.Equals(cname, "判定", StringComparison.OrdinalIgnoreCase) Then hasOld = True
                If String.Equals(cname, "E判定", StringComparison.OrdinalIgnoreCase) Then hasNew = True
            Next

            If hasNew Then
                ' 既にE判定があるので何もしない
                Return
            End If

            If hasOld Then
                Try
                    ' ADOX で直接変更を試みる
                    tbl.Columns.Item("判定").Name = "E判定"
                    MsgBox("列名を '判定' -> 'E判定' に変更しました。")
                    Return
                Catch ex As Exception
                    ' フォールバックへ
                End Try
            Else
                MsgBox("列 '判定' が見つかりません。")
                Return
            End If

            ' フォールバック: 新列追加、値コピー、旧列削除
            Try
                Using cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")
                    cn.Open()
                    Using addCmd As New OleDbCommand("ALTER TABLE [" & tableName & "] ADD COLUMN [E判定] TEXT(10)", cn)
                        addCmd.ExecuteNonQuery()
                    End Using
                    Using updCmd As New OleDbCommand("UPDATE [" & tableName & "] SET [E判定] = [判定]", cn)
                        updCmd.ExecuteNonQuery()
                    End Using
                    Using dropCmd As New OleDbCommand("ALTER TABLE [" & tableName & "] DROP COLUMN [判定]", cn)
                        dropCmd.ExecuteNonQuery()
                    End Using
                    cn.Close()
                End Using
                MsgBox("フォールバックにより '判定' を 'E判定' に移行しました。")
            Catch ex As Exception
                MsgBox("列名変更に失敗しました: " & ex.Message)
            End Try

        Catch ex As Exception
            MsgBox("Rename 判定 -> E判定 エラー: " & ex.Message)
        Finally
            ReleaseCom(cat)
        End Try
    End Sub

    ''' <summary>
    ''' T160_全出荷I集計 テーブルの列名 '判定' を 'I判定' に変更します。
    ''' ADOXで直接リネームを試み、失敗した場合はフォールバックで新列追加・コピー・旧列削除を行います。
    ''' </summary>
    Public Sub Rename判定ToI判定()
        Dim tableName As String = "T160_全出荷I集計"
        If String.IsNullOrWhiteSpace(MyDB) Then
            MsgBox("DBパス未設定のため列名変更を中止します。")
            Return
        End If

        Dim cat As ADOX.Catalog = Nothing
        Try
            cat = New ADOX.Catalog()
            cat.let_ActiveConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")

            Dim tbl As ADOX.Table = Nothing
            For i As Integer = 0 To cat.Tables.Count - 1
                If String.Equals(cat.Tables(i).Name, tableName, StringComparison.OrdinalIgnoreCase) Then
                    tbl = cat.Tables(i)
                    Exit For
                End If
            Next

            If tbl Is Nothing Then
                MsgBox("テーブル '" & tableName & "' が見つかりません。")
                Return
            End If

            Dim hasOld As Boolean = False
            Dim hasNew As Boolean = False
            For j As Integer = 0 To tbl.Columns.Count - 1
                Dim cname As String = tbl.Columns(j).Name
                If String.Equals(cname, "判定", StringComparison.OrdinalIgnoreCase) Then hasOld = True
                If String.Equals(cname, "I判定", StringComparison.OrdinalIgnoreCase) Then hasNew = True
            Next

            If hasNew Then
                ' 既に I判定 があるので何もしない
                Return
            End If

            If hasOld Then
                Try
                    tbl.Columns.Item("判定").Name = "I判定"
                    MsgBox("列名を '判定' -> 'I判定' に変更しました。")
                    Return
                Catch ex As Exception
                    ' フォールバックへ
                End Try
            Else
                MsgBox("列 '判定' が見つかりません。")
                Return
            End If

            ' フォールバック: 新列追加、値コピー、旧列削除
            Try
                Using cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")
                    cn.Open()
                    Using addCmd As New OleDbCommand("ALTER TABLE [" & tableName & "] ADD COLUMN [I判定] TEXT(10)", cn)
                        addCmd.ExecuteNonQuery()
                    End Using
                    Using updCmd As New OleDbCommand("UPDATE [" & tableName & "] SET [I判定] = [判定]", cn)
                        updCmd.ExecuteNonQuery()
                    End Using
                    Using dropCmd As New OleDbCommand("ALTER TABLE [" & tableName & "] DROP COLUMN [判定]", cn)
                        dropCmd.ExecuteNonQuery()
                    End Using
                    cn.Close()
                End Using
                MsgBox("フォールバックにより '判定' を 'I判定' に移行しました。")
            Catch ex As Exception
                MsgBox("列名変更に失敗しました: " & ex.Message)
            End Try

        Catch ex As Exception
            MsgBox("Rename 判定 -> I判定 エラー: " & ex.Message)
        Finally
            ReleaseCom(cat)
        End Try
    End Sub
    Public Sub Access閉じる(MyDB1 As String)
        Dim targetFileName As String = MyDB1
        Dim accessApp As Access.Application = Nothing

        Try
            accessApp = DirectCast(System.Runtime.InteropServices.Marshal.GetActiveObject("Access.Application"), Access.Application)

            If accessApp.CurrentProject.Name = targetFileName Then
                accessApp.Quit()
                Console.WriteLine($"{targetFileName} を終了しました。")
            End If

        Catch ex As System.Runtime.InteropServices.COMException
            ' Accessが起動していない場合は何もしない
        Finally
            If accessApp IsNot Nothing Then
                System.Runtime.InteropServices.Marshal.ReleaseComObject(accessApp)
            End If
        End Try
    End Sub
    Public Sub Access接続を確実に閉じる(MyDB As String)
        ' インポートの直前にこれを徹底してください
        GC.Collect()
        GC.WaitForPendingFinalizers()

        ' CreateObjectを使用してインスタンス化
        Dim accessApp As Access.Application = DirectCast(CreateObject("Access.Application"), Access.Application)
        Try
            ' OpenCurrentDatabase の前にファイルが存在し、ロックされていないか確認
            ' 排他モード(Exclusive:=False)で開くことで衝突を避ける
            accessApp.OpenCurrentDatabase(MyDB, Exclusive:=False)

            ' ... インポート処理 ...
        Catch ex As Exception
            ' エラー詳細を表示
            Console.WriteLine("実行エラー: " & ex.Message)
        Finally
            accessApp.Quit()
            System.Runtime.InteropServices.Marshal.ReleaseComObject(accessApp)
        End Try

    End Sub

#End Region

#Region "テーブル 作成・削除・項目追加・削除"

    ''' <summary>
    ''' Accessテーブルに新しい列を追加します。
    ''' </summary>
    Public Sub 列を追加(dbPath As String, テーブル名 As String, 列名 As String, データ型 As String)

        '<param name="dbPath">Accessファイルへのフルパス</param>
        '<param name="テーブル名">対象のテーブル名</param>
        '<param name="列名">追加したい新しい列名</param>
        '<param name="データ型">String, Double, Integer など</param>
        '
        '接続文字列（accdb形式用）
        Dim connStr As String = $"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={dbPath};"

        ' SQL上のデータ型に変換
        Dim sqlDataType As String = GetSqlDataType(データ型)

        ' SQL文の作成（ALTER TABLE テーブル名 ADD COLUMN 列名 型）
        Dim sql As String = $"ALTER TABLE [{テーブル名}] ADD COLUMN [{列名}] {sqlDataType}"

        Using conn As New OleDbConnection(connStr)
            Try
                conn.Open()
                Using cmd As New OleDbCommand(sql, conn)
                    cmd.ExecuteNonQuery()
                End Using
                Console.WriteLine("列が正常に追加されました。")
            Catch ex As Exception
                MsgBox("エラーが発生しました: " & ex.Message)
            End Try
        End Using
    End Sub
    '' <summary>
    '' 引数の文字列をAccess SQLのデータ型キーワードに変換します。
    ''' 列を追加(dbPath As String, テーブル名 As String,列名 As String, データ型 As String)から呼び出される
    ''' </summary>
    Private Function GetSqlDataType(dataType As String) As String
        Select Case dataType.ToLower()
            Case "string", "文字型", "テキスト"
                Return "LONGTEXT" ' または VARCHAR(255)
            Case "double", "数値", "実数"
                Return "DOUBLE"
            Case "integer", "整数"
                Return "INTEGER"
            Case "date", "日付"
                Return "DATETIME"
            Case "boolean", "真偽値"
                Return "YESNO"
            Case Else
                Return "VARCHAR(255)"
        End Select
    End Function

#End Region

#Region "DB ImportExce ExportExcel"
    Public Sub ImportExcelToAccess(MyDB As String, MyTable As String, MyExcel As String, MySheet As String)
        Dim dbPath As String = MyDB
        Dim excelPath As String = MyExcel
        Dim tableName As String = MyTable

        ' CreateObjectを使用してインスタンス化（他のメソッドと統一）
        Dim accessApp As Access.Application = DirectCast(CreateObject("Access.Application"), Access.Application)

        Try
            ' データベースを排他モードで開く
            accessApp.OpenCurrentDatabase(dbPath)

            ' 1. 同名テーブルが既にある場合は削除（リフレッシュするため）
            Try
                accessApp.DoCmd.DeleteObject(Access.AcObjectType.acTable, tableName)
            Catch
                ' テーブルが存在しないエラーは無視
            End Try

            ' 2. Excelインポート実行
            ' acImport: インポート, acSpreadsheetTypeExcel12Xml: .xlsx, True: 1行目をヘッダーとする
            accessApp.DoCmd.TransferSpreadsheet(
                Access.AcDataTransferType.acImport,
                Access.AcSpreadSheetType.acSpreadsheetTypeExcel12Xml,
                tableName,
                excelPath,
                HasFieldNames:=True
            )

            Console.WriteLine($"テーブル [{tableName}] の作成とインポートが完了しました。")

        Catch ex As Exception
            Console.WriteLine("実行エラー: " & ex.Message)
        Finally
            accessApp.Quit()
            System.Runtime.InteropServices.Marshal.ReleaseComObject(accessApp)
        End Try
    End Sub

#End Region

#Region "Access Query・Table削除 サーチ等”
    Public Sub DEL_Query(ByVal Query名 As String)

        '呼び出し例 DEL_Query(Q12＊）ー－＞Q12ｘｘｘはすべて削除

        'MsgBox(Query名)
        Dim cn As ADODB.Connection = DirectCast(CreateObject("ADODB.Connection"), ADODB.Connection)
        Dim cat As ADOX.Catalog
        Dim viw As ADOX.View
        'Dim tbl As ADOX.Table
        cn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" + "Data Source=" + MyDB + ";"
        cn.Open()
        cat = DirectCast(CreateObject("ADOX.Catalog"), ADOX.Catalog)
        cat.let_ActiveConnection(cn)  ' cn は ADODB.Connection オブジェクト

        Dim h(50) As String
        Dim f As Integer = 0
        Dim i As Integer = 0
        Dim L = Query名.Length
        If InStr(Query名, "*") >= 2 Then
            L = InStr(Query名, "*") - 1
            Query名 = Strings.Left(Query名, L)
        End If


        For Each viw In cat.Views
            If Strings.Left(viw.Name, L) = Query名 Then
                f += 1 : h(f) = viw.Name           'クエリー検索
            End If
        Next viw

        'For Each tbl In cat.Tables
        '    If tbl.Type = "TABLE" Then
        '        .Items.Add(tbl.Name)        'テーブル検索
        '    End If
        'Next


        For i = 1 To f
            cn.Execute("DROP VIEW " & h(i) & "") 'クエリー削除
        Next

        If cat IsNot Nothing Then
            Try
                System.Runtime.InteropServices.Marshal.ReleaseComObject(cat)
            Catch
            End Try
            cat = Nothing
        End If
        cn.Close()
        If cn IsNot Nothing Then
            Try
                System.Runtime.InteropServices.Marshal.ReleaseComObject(cn)
            Catch
            End Try
            cn = Nothing
        End If

    End Sub

    Public Sub DEL_table(ByVal Table名 As String)

        '呼び出し例 DEL_table(Ｔ12*）ー－＞Ｔ12ｘｘｘはすべて削除

        Dim cn As ADODB.Connection = Nothing
        Dim cat As ADOX.Catalog = Nothing
        If Table名 Is Nothing Then Return
        Dim a As String = If(Table名.Length >= 2, Table名.Substring(0, 2), Table名)
        If a = "MS" Or a = "ms" Then
            MsgBox("システムテーブルは削除不可")
            Return
        End If

        Try
            cn = New ADODB.Connection()
            cn.Open("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")
            cat = New ADOX.Catalog()
            cat.let_ActiveConnection(cn)

            Dim L As Integer = If(Table名.Contains("*"), Table名.IndexOf("*"), Table名.Length)
            Dim prefix As String = Table名.Substring(0, L)

            ' 逆順で削除（インデックス変動対策）
            For i As Integer = cat.Tables.Count - 1 To 0 Step -1
                Dim tblName As String = cat.Tables(i).Name
                If tblName.StartsWith(prefix) Then
                    ' ADODB.Connection 経由で DROP TABLE 実行（安全）
                    cn.Execute("DROP TABLE [" & tblName & "]")
                End If
            Next
        Catch ex As Exception
            MessageBox.Show("DEL_table エラー: " & ex.Message)
        Finally
            Try
                If cn IsNot Nothing AndAlso cn.State = 1 Then cn.Close()
            Catch
            End Try
            ReleaseCom(cat)
            ReleaseCom(cn)
            GC.Collect()
            GC.WaitForPendingFinalizers()
        End Try
    End Sub
    ''' <summary>
    ''' COMオブジェクトを安全に解放します。
    ''' </summary>
    Private Sub ReleaseCom(ByVal obj As Object)
        Try
            If obj IsNot Nothing AndAlso System.Runtime.InteropServices.Marshal.IsComObject(obj) Then
                System.Runtime.InteropServices.Marshal.FinalReleaseComObject(obj)
            End If
        Catch
        Finally
            obj = Nothing
        End Try
    End Sub


    Public Function Search_Table(ByVal Table名 As String) As Boolean
        Dim a As String = Table名.Substring(0, 2)
        If a = "MS" Or a = "ms" Then
            MsgBox("システムテーブルは対象外")
            Return False
        End If

        Dim ADOXDBCon As ADOX.Catalog = Nothing
        Try
            ADOXDBCon = New ADOX.Catalog()
            ' 修正: let_ActiveConnection メソッドを使用
            ADOXDBCon.let_ActiveConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")

            Dim i As Integer = 0
            Dim L As Integer = Table名.Length

            If a.Contains("*") = True Then
                If InStr(Table名, "*") >= 2 Then
                    L = InStr(Table名, "*") - 1
                    Table名 = Strings.Left(Table名, L)
                End If
                For i = 0 To ADOXDBCon.Tables.Count - 1
                    If Strings.Left(ADOXDBCon.Tables(i).Name, L) = Table名 Then
                        Return True
                    End If
                Next
            End If

            If a.Contains("*") = False Then
                For i = 0 To ADOXDBCon.Tables.Count - 1
                    If Table名 = ADOXDBCon.Tables(i).Name Then
                        Return True
                    End If
                Next
            End If

            Return False
        Catch ex As Exception
            MsgBox("Search_Table エラー: " & ex.Message)
            Return False
        Finally
            ' COM オブジェクトの適切な解放
            ReleaseCom(ADOXDBCon)
        End Try
    End Function

    ' EnsureColumnExists removed: direct ALTER TABLE attempts are used instead per user's preference


#End Region

#Region "  SQL実行”
    Public Sub Sqlcommands_Add(sqlCommands As List(Of String))
        Dim cn As System.Data.OleDb.OleDbConnection =
                  New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")
        Dim Com As System.Data.OleDb.OleDbCommand = New OleDb.OleDbCommand()
        Com.Connection = cn
        cn.Open()
        Com.Transaction = cn.BeginTransaction
        Try
            Dim i1 As Integer
            For i1 = 0 To sqlCommands.Count - 1
                Com.CommandText = sqlCommands(i1)
                Com.ExecuteNonQuery()
            Next
            Com.Transaction.Commit()
        Catch ex As Exception
            MessageBox.Show(ex.Message)
            Com.Transaction.Rollback()
        Finally
            cn.Close()
        End Try

    End Sub
    Public Sub SQL実行(ByVal MySql As String)
        ' 実行専用：UPDATE/INSERT/DELETE などの非クエリを正しく実行するため ExecuteNonQuery を使用します。
        Using con As New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")
            Using cmd As New OleDb.OleDbCommand(MySql, con)
                cmd.CommandType = CommandType.Text
                Try
                    con.Open()
                    Dim affected As Integer = cmd.ExecuteNonQuery()
                    ' 影響行数をログ出力（デバッグ用）。必要なければ削除可。
                    ' Debug.WriteLine($"SQL実行: {MySql} -> {affected} 行")
                Catch ex As Exception
                    Try
                        MessageBox.Show("SQL実行エラー: " & ex.Message & vbCrLf & "SQL: " & MySql)
                    Catch
                    End Try
                    Throw
                End Try
            End Using
        End Using
    End Sub



#End Region

#Region "  作業Dgv読込"


    'Public Sub 作業Dgv読込(ByVal Dgv名 As DataGridView, ByVal MySQL As String, ByVal Mytable As String)

    '    '「Imports System.Data.OleDb」設定

    '    Dim dt As New System.Data.DataTable()
    '    Dim builder As OleDbConnectionStringBuilder

    '    builder = New OleDbConnectionStringBuilder()    'Accessへの接続情報の設定をします。
    '    builder.Provider = "Microsoft.ACE.OLEDB.12.0"   'Access2007形式のファイルなのでこれを設定します。
    '    builder.DataSource = MyDB                       'Accessファイルへのパスを設定します。


    '    Using conn As New OleDbConnection(builder.ConnectionString)     '接続情報を使ってコネクションを生成します。
    '        Using cmd As New OleDbCommand(MySQL, conn)                  'SQL文とコネクションを設定します。
    '            Dim odda As OleDbDataAdapter = New OleDbDataAdapter()   'Accessファイルへの橋渡しのアダプターを設定します。
    '            odda.SelectCommand = cmd                                'SELECTコマンドを設定します。
    '            Dim rowsAffected As Integer = odda.Fill(dt)             'SELECTの実行及びフェッチ
    '            Dgv名.DataSource = dt                                 'グリッドに表示します。
    '        End Using
    '    End Using
    '    builder = Nothing
    '    '作業テーブル名Tb.Text = Mytable
    'End Sub
    'Public Sub 作業Dgvから画面Dgv表示(ByVal Dgv名 As DataGridView, ByVal 集計方法 As String)
    '    Dim i, j, iMax, jMax As Integer
    '    Dim 縦計 As Double = 0

    '    With Dgv名
    '        .Font = New System.Drawing.Font("MS UI Gothic", 9)
    '        .DefaultCellStyle.ForeColor = Color.Black
    '        .Columns.Clear()                '在庫物量推定Dgv初期化
    '        .ColumnHeadersVisible = False   '列ヘッダーを非表示に設定
    '        .RowHeadersVisible = False      '行ヘッダーを非表示に設定
    '        .AllowUserToAddRows = False     '最下部の新しい行を非表示にする
    '        .ColumnHeadersDefaultCellStyle.Alignment =
    '                              DataGridViewContentAlignment.MiddleCenter  '列中央寄せMiddleCenter 右寄せMiddleRight
    '        .AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells        'ヘッダーとすべてのセルの内容に合わせて、行の高さを自動調整する


    '        jMax = Dgv名.Columns.Count : .ColumnCount = jMax
    '        iMax = Dgv名.Rows.Count : .RowCount = jMax - 1


    '        For j = 0 To jMax - 1
    '            .Item(j, 0).Value = Dgv名.Columns(j).HeaderText
    '            .Columns(j).DefaultCellStyle.Format = "#,0"
    '            .Columns(j).HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter
    '        Next
    '        .Rows(0).DefaultCellStyle.BackColor = Color.Gainsboro
    '        .Rows(iMax).DefaultCellStyle.BackColor = Color.Gainsboro

    '        For j = 0 To jMax - 1
    '            .Columns(j).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
    '            For i = 0 To iMax - 1
    '                If i < 1 Or j < 1 Then
    '                    .Item(j, i + 1).Value = Dgv名.Item(j, i).Value
    '                Else
    '                    .Item(j, i + 1).Value = CDbl(Dgv名.Item(j, i).Value)
    '                    縦計 += CDbl(Dgv名.Item(j, i).Value)
    '                End If
    '            Next
    '            If j > 0 Then .Item(j, i).Value = 縦計 : 縦計 = 0
    '        Next

    '        If 集計方法 = "縦計" Then
    '            .Item(0, iMax).Value = "縦計"
    '        End If

    '    End With

    'End Sub
    '    Public Sub Dgv表示1(ByVal Dgv名 As DataGridView, ByVal MySQL As String, ByVal Mytable As String)
    '        'ADO.NET,SQLでDgv表示

    '        Dim dt As New System.Data.DataTable()
    '        Dim builder As OleDbConnectionStringBuilder = New OleDbConnectionStringBuilder()      'Accessへの接続情報の設定。
    '        builder.Provider = "Microsoft.ACE.OLEDB.12.0"                  'Access2007形式で設定。
    '        'builder.Provider = "Microsoft.ACE.OLEDB.16.0"                  'Access2016形式で設定。

    '        builder.DataSource = MyDB                                      'Accessファイルへのパスを設定。 

    '        With Dgv名
    '            'Dgv表示
    '            Using conn As New OleDbConnection(builder.ConnectionString)    '接続情報を使ってコネクションを生成。
    '                Using cmd As New OleDbCommand(MySQL, conn)                 'SQL文とコネクションを設定。

    '                    Dim odda As OleDbDataAdapter = New OleDbDataAdapter()  'Accessファイルへの橋渡しのアダプターを設定。
    '                    odda.SelectCommand = cmd                               'SELECTコマンドを設定。
    '                    odda.Fill(dt)                                          'SELECTの実行及びフェッチ
    '                    .DataSource = dt                                       'Dgvに表示。
    '                End Using
    '            End Using
    '        End With


    '        With Dgv名
    '            If .ColumnCount - 1 <= 100 Then '成形に時間がかかる

    '                'Dgv書式
    '                ' .Columns.Clear() : .Rows.Clear()            '在庫物量推定Dgv初期化
    '                '.ColumnHeadersVisible = False                '列ヘッダーを非表示に設定
    '                .RowHeadersVisible = False                    '行ヘッダーを非表示に設定
    '                .AllowUserToAddRows = False                   '最下部の新しい行を非表示にする

    '                .ColumnHeadersDefaultCellStyle.Alignment _
    '                  = DataGridViewContentAlignment.MiddleCenter '列ヘッダーの項目名を中央揃え

    '                Dim d As Double

    '                For i = 0 To .ColumnCount - 1
    '                    'Doubleに変換できるか確かめ,桁表示を設定
    '                    On Error GoTo ErrorHandler

    '                    Double.TryParse(CStr(.Item(i, 0).Value), d)
    '                    ' MsgBox(d)
    '                    If d > 0 Then
    '                        .Columns(i).DefaultCellStyle.Alignment = DataGridViewContentAlignment.BottomRight
    '                        If d < 0.001 Then .Columns(i).DefaultCellStyle.Format = ("n4")
    '                        If d < 0.01 Then .Columns(i).DefaultCellStyle.Format = ("n3")
    '                        If d < 0.1 Then .Columns(i).DefaultCellStyle.Format = ("n2")
    '                        If d < 1 Then .Columns(i).DefaultCellStyle.Format = ("n1")
    '                        If d >= 1 Then .Columns(i).DefaultCellStyle.Format = ("n0")
    '                    Else
    '                        .Columns(i).DefaultCellStyle.Alignment = DataGridViewContentAlignment.BottomLeft
    '                    End If
    'ErrorHandler:

    '                Next

    '                .AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells  'ヘッダーとすべてのセルの内容に合わせて、列の幅を自動調整する
    '                .AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells        'ヘッダーとすべてのセルの内容に合わせて、行の高さを自動調整する

    '            End If
    '        End With
    '    End Sub
    '    Public Sub Dgv表示(ByVal MyDgv As DataGridView, ByVal MySQL As String)

    '        MyDgv.Columns.Clear()                   'MyDgv初期化  (MyDgv.Rows.Clear()は不要）
    '        MyDgv.RowHeadersVisible = False         '行ヘッダーを非表示に設定
    '        '「Imports System.Data.OleDb」設定
    '        Dim dt As New System.Data.DataTable()
    '        Dim builder As OleDbConnectionStringBuilder

    '        builder = New OleDbConnectionStringBuilder()    'Accessへの接続情報の設定をいます。
    '        builder.Provider = "Microsoft.ACE.OLEDB.12.0"   'Access2007形式のファイルなのでこれを設定します。
    '        builder.DataSource = MyDB                       'Accessファイルへのパスを設定します。

    '        Using conn As New OleDbConnection(builder.ConnectionString)     '接続情報を使ってコネクションを生成します。
    '            Using cmd As New OleDbCommand(MySQL, conn)                  'SQL文とコネクションを設定します。
    '                Dim odda As OleDbDataAdapter = New OleDbDataAdapter()   'Accessファイルへの橋渡しのアダプターを設定します。
    '                odda.SelectCommand = cmd                                'SELECTコマンドを設定します。
    '                odda.Fill(dt)                                           'SELECTの実行及びフェッチ
    '                MyDgv.DataSource = dt                                 'グリッドに表示します。
    '            End Using
    '        End Using
    '        builder = Nothing
    '    End Sub
#End Region


    Public Sub 乱数追加()
        Dim ss As Integer = 0
        Dim tables As String() = {
            "T150_B単位出荷E集計",
            "T150_B単位出荷I集計",
            "T150_C単位出荷E集計",
            "T150_C単位出荷I集計",
            "T160_全出荷E集計",
            "T160_全出荷I集計"
        }

        If String.IsNullOrWhiteSpace(MyDB) Then
            MsgBox("DBパスが未設定のため乱数追加を中止します。")
            Return
        End If

        Try
            ' ADOXでテーブル情報を取得（リンク判定のため）
            Dim catalog As New ADOX.Catalog()
            catalog.let_ActiveConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")

            ' --- 1) まず各テーブルに「乱数」列がなければ追加（可能な限り） ---
            For Each t As String In tables
                If Not Search_Table(t) Then Continue For
                ss += 1
                Try
                    Dim isLinked As Boolean = False
                    Dim remoteDatasource As String = MyDB
                    Dim remoteTableName As String = t

                    For i As Integer = 0 To catalog.Tables.Count - 1
                        If String.Equals(catalog.Tables(i).Name, t, StringComparison.OrdinalIgnoreCase) Then
                            Try
                                Dim props = catalog.Tables(i).Properties
                                If props.Item("Jet OLEDB:Create Link") IsNot Nothing AndAlso
                                   CBool(props.Item("Jet OLEDB:Create Link").Value) = True Then
                                    isLinked = True
                                    Try
                                        remoteDatasource = props.Item("Jet OLEDB:Link Datasource").Value.ToString()
                                    Catch
                                    End Try
                                    Try
                                        remoteTableName = props.Item("Jet OLEDB:Remote Table Name").Value.ToString()
                                    Catch
                                    End Try
                                End If
                            Catch
                                ' プロパティ参照失敗は無視
                            End Try
                            Exit For
                        End If
                    Next

                    Using cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & remoteDatasource & ";")
                        cn.Open()

                        ' スキーマ取得で列存在を確認
                        Dim colExists As Boolean = False
                        Using schemaCmd As New OleDbCommand("SELECT * FROM [" & remoteTableName & "] WHERE 1=0", cn)
                            Using rdr As OleDbDataReader = schemaCmd.ExecuteReader(CommandBehavior.SchemaOnly)
                                Dim dtSchema As DataTable = rdr.GetSchemaTable()
                                If dtSchema IsNot Nothing Then
                                    For Each row As DataRow In dtSchema.Rows
                                        If String.Equals(row("ColumnName").ToString(), "乱数", StringComparison.OrdinalIgnoreCase) Then
                                            colExists = True
                                            Exit For
                                        End If
                                    Next
                                End If
                            End Using
                        End Using

                        If Not colExists Then
                            Try
                                Dim addCmd As New OleDbCommand("ALTER TABLE [" & remoteTableName & "] ADD COLUMN 乱数 DOUBLE", cn)
                                addCmd.ExecuteNonQuery()
                            Catch ex As Exception
                                ' 次のテーブルへ


                                Continue For
                            End Try
                        End If

                        cn.Close()
                    End Using
                Catch ex As Exception

                End Try
            Next

            ' --- 2) 乱数割当（順位が無ければ 出荷先/アイテム を使って更新） ---
            ' 再現性のある乱数列にするため固定シードを利用
            ' 必要なら My_DATA1 の 分析日 や MyDB パスからシードを算出するよう変更可能
            Dim seed As Integer = 123456
            Dim rnd As New Random(seed) ' 固定シード（毎回同じ乱数列）

            For Each t As String In tables
                If Not Search_Table(t) Then Continue For

                ' 再度 ADOX でリンク先を決定
                Dim catalog2 As New ADOX.Catalog()
                catalog2.let_ActiveConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")
                Dim remoteDatasource As String = MyDB
                Dim remoteTableName As String = t

                For i As Integer = 0 To catalog2.Tables.Count - 1
                    If String.Equals(catalog2.Tables(i).Name, t, StringComparison.OrdinalIgnoreCase) Then
                        Try
                            Dim props = catalog2.Tables(i).Properties
                            If props.Item("Jet OLEDB:Create Link") IsNot Nothing AndAlso
                               CBool(props.Item("Jet OLEDB:Create Link").Value) = True Then
                                Try
                                    remoteDatasource = props.Item("Jet OLEDB:Link Datasource").Value.ToString()
                                Catch
                                End Try
                                Try
                                    remoteTableName = props.Item("Jet OLEDB:Remote Table Name").Value.ToString()
                                Catch
                                End Try
                            End If
                        Catch
                        End Try
                        Exit For
                    End If
                Next

                Try
                    Using cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & remoteDatasource & ";")
                        cn.Open()

                        ' スキーマで利用可能なキー列を判定（順位、出荷先、アイテムの順）
                        Dim hasJuni As Boolean = False, hasDest As Boolean = False, hasItem As Boolean = False
                        Using schemaCmd As New OleDbCommand("SELECT * FROM [" & remoteTableName & "] WHERE 1=0", cn)
                            Using rdr As OleDbDataReader = schemaCmd.ExecuteReader(CommandBehavior.SchemaOnly)
                                Dim dtSchema As DataTable = rdr.GetSchemaTable()
                                If dtSchema IsNot Nothing Then
                                    For Each row As DataRow In dtSchema.Rows
                                        Dim cname = row("ColumnName").ToString()
                                        If String.Equals(cname, "順位", StringComparison.OrdinalIgnoreCase) Then hasJuni = True
                                        If String.Equals(cname, "出荷先", StringComparison.OrdinalIgnoreCase) Then hasDest = True
                                        If String.Equals(cname, "アイテム", StringComparison.OrdinalIgnoreCase) Then hasItem = True
                                    Next
                                End If
                            End Using
                        End Using

                        ' 更新に使う列がない場合はスキップ
                        If Not (hasJuni Or hasDest Or hasItem) Then
                            Continue For
                        End If

                        ' 読み取り用 SQL を組立て
                        Dim selectCols As New List(Of String)
                        If hasJuni Then selectCols.Add("[順位]")
                        If hasDest Then selectCols.Add("[出荷先]")
                        If hasItem Then selectCols.Add("[アイテム]")
                        Dim selSql As String = "SELECT " & String.Join(", ", selectCols.ToArray()) & " FROM [" & remoteTableName & "]"

                        ' 読み取りを先に完了させ、更新は Reader を閉じた後に実行する（ロック回避）
                        Dim rows As New List(Of Dictionary(Of String, Object))()
                        Using selCmd As New OleDbCommand(selSql, cn)
                            Using rdr As OleDbDataReader = selCmd.ExecuteReader()
                                While rdr.Read()
                                    Dim rowData As New Dictionary(Of String, Object)()
                                    For col As Integer = 0 To rdr.FieldCount - 1
                                        rowData(rdr.GetName(col)) = rdr(col)
                                    Next
                                    rows.Add(rowData)
                                End While
                            End Using
                        End Using

                        If rows.Count = 0 Then Continue For

                        ' 更新コマンドを用意（各キー別）
                        Dim updJ As New OleDbCommand("UPDATE [" & remoteTableName & "] SET 乱数 = ? WHERE [順位] = ?", cn)
                        updJ.Parameters.Add(New OleDbParameter("?", OleDbType.Double))
                        updJ.Parameters.Add(New OleDbParameter("?", OleDbType.Integer))

                        Dim updDest As New OleDbCommand("UPDATE [" & remoteTableName & "] SET 乱数 = ? WHERE [出荷先] = ?", cn)
                        updDest.Parameters.Add(New OleDbParameter("?", OleDbType.Double))
                        updDest.Parameters.Add(New OleDbParameter("?", OleDbType.VarChar, 255))

                        Dim updItem As New OleDbCommand("UPDATE [" & remoteTableName & "] SET 乱数 = ? WHERE [アイテム] = ?", cn)
                        updItem.Parameters.Add(New OleDbParameter("?", OleDbType.Double))
                        updItem.Parameters.Add(New OleDbParameter("?", OleDbType.VarChar, 255))

                        Dim trans As OleDb.OleDbTransaction = cn.BeginTransaction()
                        updJ.Transaction = trans
                        updDest.Transaction = trans
                        updItem.Transaction = trans

                        Try
                            For Each rowData As Dictionary(Of String, Object) In rows
                                Dim val As Double = rnd.NextDouble()
                                If hasJuni AndAlso rowData.ContainsKey("順位") AndAlso Not IsDBNull(rowData("順位")) Then
                                    Try
                                        updJ.Parameters(0).Value = val
                                        updJ.Parameters(1).Value = Convert.ToInt32(rowData("順位"))
                                        updJ.ExecuteNonQuery()
                                    Catch
                                        ' 個別更新失敗は行を飛ばす
                                    End Try
                                ElseIf hasDest AndAlso rowData.ContainsKey("出荷先") AndAlso Not IsDBNull(rowData("出荷先")) Then
                                    Try
                                        updDest.Parameters(0).Value = val
                                        updDest.Parameters(1).Value = rowData("出荷先").ToString()
                                        updDest.ExecuteNonQuery()
                                    Catch
                                    End Try
                                ElseIf hasItem AndAlso rowData.ContainsKey("アイテム") AndAlso Not IsDBNull(rowData("アイテム")) Then
                                    Try
                                        updItem.Parameters(0).Value = val
                                        updItem.Parameters(1).Value = rowData("アイテム").ToString()
                                        updItem.ExecuteNonQuery()
                                    Catch
                                    End Try
                                End If
                            Next

                            trans.Commit()
                        Catch ex As Exception
                            trans.Rollback()
                            Throw
                        Finally
                            updJ.Dispose()
                            updDest.Dispose()
                            updItem.Dispose()
                        End Try

                        cn.Close()
                    End Using
                Catch ex As Exception

                End Try
            Next


        Catch ex As Exception

        End Try
    End Sub

    Public Sub T150_T160に判定を追加()
        'Dim tables As String() = {
        '    "T150_B単位出荷E集計",
        '    "T150_B単位出荷I集計",
        '    "T150_C単位出荷E集計",
        '    "T150_C単位出荷I集計",
        '    "T160_全出荷E集計",
        '    "T160_全出荷I集計"
        '}
        Dim tables As String() = {
          "T160_全出荷E集計",
          "T160_全出荷I集計"
        }

        If String.IsNullOrWhiteSpace(MyDB) Then
            MsgBox("DBパスが未設定のため判定列追加を中止します。")
            Return
        End If

        For Each t As String In tables
            If Not Search_Table(t) Then Continue For
            Try
                Using cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")
                    cn.Open()

                    ' 判定列名をテーブル種別に応じて決定 (E集計 -> E判定, I集計 -> I判定)
                    Dim targetCol As String = "判定"
                    If t.IndexOf("E集計", StringComparison.OrdinalIgnoreCase) >= 0 Then
                        targetCol = "E判定"
                    ElseIf t.IndexOf("I集計", StringComparison.OrdinalIgnoreCase) >= 0 Then
                        targetCol = "I判定"
                    End If

                    ' スキーマ取得で列存在を確認
                    Dim colExists As Boolean = False
                    Using schemaCmd As New OleDbCommand("SELECT * FROM [" & t & "] WHERE 1=0", cn)
                        Using rdr As OleDbDataReader = schemaCmd.ExecuteReader(CommandBehavior.SchemaOnly)
                            Dim dtSchema As DataTable = rdr.GetSchemaTable()
                            If dtSchema IsNot Nothing Then
                                For Each row As DataRow In dtSchema.Rows
                                    If String.Equals(row("ColumnName").ToString(), targetCol, StringComparison.OrdinalIgnoreCase) Then
                                        colExists = True
                                        Exit For
                                    End If
                                Next
                            End If
                        End Using
                    End Using

                    If Not colExists Then
                        Try
                            Using addCmd As New OleDbCommand("ALTER TABLE [" & t & "] ADD COLUMN [" & targetCol & "] TEXT(10)", cn)
                                addCmd.ExecuteNonQuery()
                            End Using
                        Catch ex As Exception
                            ' ALTER TABLE が失敗した場合は個別に無視
                        End Try
                    End If

                    cn.Close()
                End Using
            Catch ex As Exception
                ' 個別テーブル処理失敗は無視して次へ
            End Try
        Next

    End Sub

    Public Sub T160_全出荷E集計作成(Table名 As String, 計算条件 As Integer, 計算E数 As Integer, E採用判定値 As Double)
        Dim sval As Double
        Dim MySQL As String = ""

        ' Try to add ECHK column; ignore errors if it already exists or cannot be added
        Try
            Using cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")
                cn.Open()
                Try
                    Using addCmd As New OleDbCommand("ALTER TABLE [" & Table名 & "] ADD COLUMN [ECHK] TEXT(1)", cn)
                        addCmd.ExecuteNonQuery()
                    End Using
                Catch
                    ' ignore if column exists or cannot be added
                End Try
                cn.Close()
            End Using
        Catch
        End Try
        If E採用判定値 > 1 Then
            sval = E採用判定値 - 1
            MySQL = "UPDATE [" & Table名 & "] SET [E判定] = IIf([乱数] <= " & sval & ", 'Yes', 'No'),[ECHK] = '*';"
        Else
            sval = E採用判定値
            MySQL = "UPDATE [" & Table名 & "] SET [E判定] = IIf([乱数] <= " & sval & ", 'Yes', 'No'),[ECHK] = '';"
        End If

        SQL実行(MySQL)
    End Sub
    Public Sub T160_全出荷I集計作成(Table名 As String, 計算条件 As Integer, 計算I数 As Integer, I採用判定値 As Double)
        Dim sval As Double
        Dim MySQL As String = ""

        ' Try to add ICHK column; ignore errors if it already exists or cannot be added
        Try
            Using cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")
                cn.Open()
                Try
                    Using addCmd As New OleDbCommand("ALTER TABLE [" & Table名 & "] ADD COLUMN [ICHK] TEXT(1)", cn)
                        addCmd.ExecuteNonQuery()
                    End Using
                Catch
                    ' ignore if column exists or cannot be added
                End Try
                cn.Close()
            End Using
        Catch
        End Try
        If I採用判定値 > 1 Then
            sval = I採用判定値 - 1
            MySQL = "UPDATE [" & Table名 & "] SET [I判定] = IIf([乱数] <= " & sval & ", 'Yes', 'No'),[ICHK] = '*';"
        Else
            sval = I採用判定値
            MySQL = "UPDATE [" & Table名 & "] SET [I判定] = IIf([乱数] <= " & sval & ", 'Yes', 'No'),[ICHK] = '';"
        End If

        SQL実行(MySQL)
    End Sub

    Public Function GetMissingColumns(tableName As String, requiredColumns() As String) As String()
        If String.IsNullOrWhiteSpace(tableName) Then Return requiredColumns
        Try
            Using cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")
                cn.Open()
                Using cmd As New OleDbCommand("SELECT * FROM [" & tableName & "] WHERE 1=0", cn)
                    Using rdr As OleDbDataReader = cmd.ExecuteReader(CommandBehavior.SchemaOnly)
                        Dim schema As DataTable = rdr.GetSchemaTable()
                        Dim present As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)
                        If schema IsNot Nothing Then
                            For Each row As DataRow In schema.Rows
                                present.Add(CStr(row("ColumnName")))
                            Next
                        End If

                        Dim missing As New List(Of String)
                        For Each col As String In requiredColumns
                            If Not present.Contains(col) Then missing.Add(col)
                        Next

                        Return missing.ToArray()
                    End Using
                End Using
            End Using
        Catch ex As Exception
            ' 接続やクエリに失敗した場合はエラー内容を表示して全カラム不足扱いにする
            MessageBox.Show("列チェックエラー: " & ex.Message)
            Return requiredColumns
        End Try
    End Function


    Public Sub T350_計算対象作成(進行連番 As Integer, E採用判定値 As Double, I採用判定値 As Double)
        ' 1. T500* テーブルを削除
        DEL_table("T500*")

        ' 2. T350_計算対象 を新規作成（指定列定義）
        MySQL = "CREATE TABLE T350_計算対象 (" &
                "進行連番 INTEGER, " &
                "GPLEランク TEXT(10), " &
                "GPLIランク TEXT(10), " &
                "行連番 INTEGER, " &
                "出荷先 TEXT(20), " &
                "アイテム TEXT(20), " &
                "G行 DOUBLE, " &
                "Gバ DOUBLE, " &
                "Gケ DOUBLE, " &
                "GPL DOUBLE, " &
                "G容 DOUBLE, " &
                "G重 DOUBLE)"
        SQL実行(MySQL)

        ' 3. 採用判定値に応じてデータを投入
        If E採用判定値 <= 1 And I採用判定値 <= 1 Then
            ' E・I ともに全採用（乱数フィルタのみ）
            ' T200 を T160_全出荷E集計（出荷先）・T160_全出荷I集計（アイテム）と結合し
            ' E判定='Yes' かつ I判定='Yes' のレコードを T350_計算対象 へ挿入
            MySQL = "INSERT INTO T350_計算対象 " &
                    "(進行連番, 行連番, 出荷先, アイテム, G行, Gバ, Gケ, GPL, G容, G重) " &
                    "SELECT " & 進行連番 & ", T200.行連番, T200.出荷先, T200.アイテム, " &
                    "T200.G行, T200.Gバ, T200.Gケ, T200.GPL, T200.G容, T200.G重 " &
                    "FROM (T200 " &
                    "INNER JOIN T160_全出荷E集計 ON T200.出荷先 = T160_全出荷E集計.出荷先) " &
                    "INNER JOIN T160_全出荷I集計 ON T200.アイテム = T160_全出荷I集計.アイテム " &
                    "WHERE T160_全出荷E集計.E判定 = 'Yes' AND T160_全出荷I集計.I判定 = 'Yes';"
            SQL実行(MySQL)
        End If

        If E採用判定値 > 1 And I採用判定値 <= 1 Then
            ' 1. E採用判定値A = E採用判定値 - 1 で T160_全出荷E集計A を作成
            Dim E採用判定値A As Double = E採用判定値 - 1
            T160_全出荷E集計A作成(E採用判定値A)

            ' 2. T160_全出荷E集計A（E判定=Yes）× T160_全出荷I集計（I判定=Yes）
            '    出荷先に "A" を付加してレコード追加
            MySQL = "INSERT INTO T350_計算対象 " &
                    "(進行連番, 行連番, 出荷先, アイテム, G行, Gバ, Gケ, GPL, G容, G重) " &
                    "SELECT " & 進行連番 & ", T200.行連番, T200.出荷先 & 'A', T200.アイテム, " &
                    "T200.G行, T200.Gバ, T200.Gケ, T200.GPL, T200.G容, T200.G重 " &
                    "FROM (T200 " &
                    "INNER JOIN T160_全出荷E集計A ON T200.出荷先 = T160_全出荷E集計A.出荷先) " &
                    "INNER JOIN T160_全出荷I集計 ON T200.アイテム = T160_全出荷I集計.アイテム " &
                    "WHERE T160_全出荷E集計A.E判定 = 'Yes' AND T160_全出荷I集計.I判定 = 'Yes';"
            SQL実行(MySQL)

            ' 3. T160_全出荷E集計（E判定 Yes/No 問わず）× T160_全出荷I集計（I判定=Yes）
            '    出荷先はそのままレコード追加
            MySQL = "INSERT INTO T350_計算対象 " &
                    "(進行連番, 行連番, 出荷先, アイテム, G行, Gバ, Gケ, GPL, G容, G重) " &
                    "SELECT " & 進行連番 & ", T200.行連番, T200.出荷先, T200.アイテム, " &
                    "T200.G行, T200.Gバ, T200.Gケ, T200.GPL, T200.G容, T200.G重 " &
                    "FROM (T200 " &
                    "INNER JOIN T160_全出荷E集計 ON T200.出荷先 = T160_全出荷E集計.出荷先) " &
                    "INNER JOIN T160_全出荷I集計 ON T200.アイテム = T160_全出荷I集計.アイテム " &
                    "WHERE T160_全出荷I集計.I判定 = 'Yes';"
            SQL実行(MySQL)
        End If

        If E採用判定値 <= 1 And I採用判定値 > 1 Then
            ' 1. I採用判定値A = I採用判定値 - 1 で T160_全出荷I集計A を作成
            Dim I採用判定値A As Double = I採用判定値 - 1
            T160_全出荷I集計A作成(I採用判定値A)

            ' 2. T160_全出荷I集計A（I判定=Yes）× T160_全出荷E集計（E判定=Yes）
            '    アイテムに "A" を付加してレコード追加
            MySQL = "INSERT INTO T350_計算対象 " &
                    "(進行連番, 行連番, 出荷先, アイテム, G行, Gバ, Gケ, GPL, G容, G重) " &
                    "SELECT " & 進行連番 & ", T200.行連番, T200.出荷先, T200.アイテム & 'A', " &
                    "T200.G行, T200.Gバ, T200.Gケ, T200.GPL, T200.G容, T200.G重 " &
                    "FROM (T200 " &
                    "INNER JOIN T160_全出荷E集計 ON T200.出荷先 = T160_全出荷E集計.出荷先) " &
                    "INNER JOIN T160_全出荷I集計A ON T200.アイテム = T160_全出荷I集計A.アイテム " &
                    "WHERE T160_全出荷I集計A.I判定 = 'Yes' AND T160_全出荷E集計.E判定 = 'Yes';"
            SQL実行(MySQL)

            ' 3. T160_全出荷I集計（I判定 Yes/No 問わず）× T160_全出荷E集計（E判定=Yes）
            '    アイテムはそのままレコード追加
            MySQL = "INSERT INTO T350_計算対象 " &
                    "(進行連番, 行連番, 出荷先, アイテム, G行, Gバ, Gケ, GPL, G容, G重) " &
                    "SELECT " & 進行連番 & ", T200.行連番, T200.出荷先, T200.アイテム, " &
                    "T200.G行, T200.Gバ, T200.Gケ, T200.GPL, T200.G容, T200.G重 " &
                    "FROM (T200 " &
                    "INNER JOIN T160_全出荷E集計 ON T200.出荷先 = T160_全出荷E集計.出荷先) " &
                    "INNER JOIN T160_全出荷I集計 ON T200.アイテム = T160_全出荷I集計.アイテム " &
                    "WHERE T160_全出荷E集計.E判定 = 'Yes';"
            SQL実行(MySQL)
        End If

        If E採用判定値 > 1 And I採用判定値 > 1 Then
            ' 1. A テーブルを両方作成
            Dim I採用判定値A As Double = I採用判定値 - 1
            T160_全出荷I集計A作成(I採用判定値A)
            Dim E採用判定値A As Double = E採用判定値 - 1
            T160_全出荷E集計A作成(E採用判定値A)

            ' 2a. T160_全出荷I集計A（I判定=Yes）× T160_全出荷E集計（E判定=Yes）
            '     アイテムに "A" を付加してレコード追加
            MySQL = "INSERT INTO T350_計算対象 " &
                    "(進行連番, 行連番, 出荷先, アイテム, G行, Gバ, Gケ, GPL, G容, G重) " &
                    "SELECT " & 進行連番 & ", T200.行連番, T200.出荷先, T200.アイテム & 'A', " &
                    "T200.G行, T200.Gバ, T200.Gケ, T200.GPL, T200.G容, T200.G重 " &
                    "FROM (T200 " &
                    "INNER JOIN T160_全出荷E集計 ON T200.出荷先 = T160_全出荷E集計.出荷先) " &
                    "INNER JOIN T160_全出荷I集計A ON T200.アイテム = T160_全出荷I集計A.アイテム " &
                    "WHERE T160_全出荷I集計A.I判定 = 'Yes' AND T160_全出荷E集計.E判定 = 'Yes';"
            SQL実行(MySQL)

            ' 2b. T160_全出荷E集計A（E判定=Yes）× T160_全出荷I集計（I判定=Yes）
            '     出荷先に "A" を付加してレコード追加
            MySQL = "INSERT INTO T350_計算対象 " &
                    "(進行連番, 行連番, 出荷先, アイテム, G行, Gバ, Gケ, GPL, G容, G重) " &
                    "SELECT " & 進行連番 & ", T200.行連番, T200.出荷先 & 'A', T200.アイテム, " &
                    "T200.G行, T200.Gバ, T200.Gケ, T200.GPL, T200.G容, T200.G重 " &
                    "FROM (T200 " &
                    "INNER JOIN T160_全出荷E集計A ON T200.出荷先 = T160_全出荷E集計A.出荷先) " &
                    "INNER JOIN T160_全出荷I集計 ON T200.アイテム = T160_全出荷I集計.アイテム " &
                    "WHERE T160_全出荷E集計A.E判定 = 'Yes' AND T160_全出荷I集計.I判定 = 'Yes';"
            SQL実行(MySQL)

            ' 3. T200 全レコードをそのまま追加（E/I 判定条件なし）
            MySQL = "INSERT INTO T350_計算対象 " &
                    "(進行連番, 行連番, 出荷先, アイテム, G行, Gバ, Gケ, GPL, G容, G重) " &
                    "SELECT " & 進行連番 & ", T200.行連番, T200.出荷先, T200.アイテム, " &
                    "T200.G行, T200.Gバ, T200.Gケ, T200.GPL, T200.G容, T200.G重 " &
                    "FROM T200;"
            SQL実行(MySQL)
        End If
    End Sub
    Public Sub T160_全出荷E集計A作成(E採用判定値A As Double)

        ' 1. T160_全出荷E集計A が存在すれば削除
        If Search_Table("T160_全出荷E集計A") Then
            DEL_table("T160_全出荷E集計A")
        End If
        ' 2. T160_全出荷E集計 をコピーして T160_全出荷E集計A を作成
        MySQL = "SELECT * INTO [T160_全出荷E集計A] FROM [T160_全出荷E集計]"
        SQL実行(MySQL)
        ' 3. E採用判定値A で E判定 を更新
        MySQL = "UPDATE [T160_全出荷E集計A] SET [E判定] = IIf([乱数] <= " & E採用判定値A & ", 'Yes', 'No'), [ECHK] = '*';"
        SQL実行(MySQL)

    End Sub

    Public Sub T160_全出荷I集計A作成(I採用判定値A As Double)

        ' 1. T160_全出荷I集計A が存在すれば削除
        If Search_Table("T160_全出荷I集計A") Then
            DEL_table("T160_全出荷I集計A")
        End If

        ' 2. T160_全出荷I集計 をコピーして T160_全出荷I集計A を作成
        MySQL = "SELECT * INTO [T160_全出荷I集計A] FROM [T160_全出荷I集計]"
        SQL実行(MySQL)

        ' 3. I採用判定値A で I判定 を更新
        MySQL = "UPDATE [T160_全出荷I集計A] SET [I判定] = IIf([乱数] <= " & I採用判定値A & ", 'Yes', 'No');"
        SQL実行(MySQL)

    End Sub

    Public Sub T360_Eランク付け()

        ' ===== 1. T360* テーブルを削除 =====
        DEL_table("T360*")

        ' ===== 2. T360_全出荷E集計 を 出荷先 × GPL合計 で作成 =====
        MySQL = "SELECT 出荷先, Sum(GPL) AS GPL合計 INTO [T360_全出荷E集計] " &
                "FROM T350_計算対象 " &
                "GROUP BY 出荷先"
        SQL実行(MySQL)

        ' ===== 3. GPLEランク 列を追加 =====
        Try
            Using cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")
                cn.Open()
                Using addCmd As New OleDbCommand(
                    "ALTER TABLE [T360_全出荷E集計] ADD COLUMN [GPLEランク] TEXT(10)", cn)
                    addCmd.ExecuteNonQuery()
                End Using
            End Using
        Catch
            ' 列が既に存在する場合は無視
        End Try

        ' ===== 4. GPL合計 を降順に読み込み累積比率でランク付け =====
        Dim connStr As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";"

        ' 4-1. GPL 全合計を取得
        Dim totalGPL As Double = 0
        Try
            Using cn As New OleDbConnection(connStr)
                cn.Open()
                Using cmd As New OleDbCommand(
                    "SELECT Sum(GPL合計) FROM [T360_全出荷E集計]", cn)
                    Dim result As Object = cmd.ExecuteScalar()
                    If result IsNot Nothing AndAlso Not IsDBNull(result) Then
                        totalGPL = Convert.ToDouble(result)
                    End If
                End Using
            End Using
        Catch ex As Exception
            MsgBox("T400_ランク付け: GPL合計取得エラー: " & ex.Message)
            Return
        End Try

        If totalGPL = 0 Then
            MsgBox("T400_ランク付け: T360_全出荷E集計 の GPL合計が 0 です。処理を中止します。")
            Return
        End If

        ' 4-2. ランク閾値（累積比率 %）を定義
        EIQ_A1ランク = 50 : EIQ_A2ランク = 20 : EIQ_Bランク = 15 : EIQ_Cランク = 10 : EIQ_Dランク = 5
        Dim th_A1 As Double = EIQ_A1ランク                                      ' 50
        Dim th_A2 As Double = EIQ_A1ランク + EIQ_A2ランク                       ' 70
        Dim th_B As Double = EIQ_A1ランク + EIQ_A2ランク + EIQ_Bランク         ' 85
        Dim th_C As Double = EIQ_A1ランク + EIQ_A2ランク + EIQ_Bランク + EIQ_Cランク ' 95
        Dim th_D As Double = 100 ' 残り全て

        ' 4-3. GPL合計 降順で読み込みながら累積比率を計算してランクを UPDATE
        Try
            Using cn As New OleDbConnection(connStr)
                cn.Open()

                Dim 累積GPL As Double = 0

                Using selCmd As New OleDbCommand(
                    "SELECT 出荷先, GPL合計 FROM [T360_全出荷E集計] ORDER BY GPL合計 DESC", cn)
                    Using rdr As OleDbDataReader = selCmd.ExecuteReader()

                        Dim updCmd As New OleDbCommand(
                            "UPDATE [T360_全出荷E集計] SET [GPLEランク] = ? WHERE [出荷先] = ?", cn)
                        updCmd.Parameters.Add(New OleDbParameter("?", OleDbType.VarChar, 10))
                        updCmd.Parameters.Add(New OleDbParameter("?", OleDbType.VarChar, 20))

                        While rdr.Read()
                            Dim dest As String = rdr("出荷先").ToString()
                            Dim gpl As Double = If(IsDBNull(rdr("GPL合計")), 0, Convert.ToDouble(rdr("GPL合計")))

                            累積GPL += gpl
                            Dim 累積比率 As Double = (累積GPL / totalGPL) * 100.0

                            Dim rank As String
                            If 累積比率 <= th_A1 Then
                                rank = "GPLE_A1"
                            ElseIf 累積比率 <= th_A2 Then
                                rank = "GPLE_A2"
                            ElseIf 累積比率 <= th_B Then
                                rank = "GPLE_B"
                            ElseIf 累積比率 <= th_C Then
                                rank = "GPLE_C"
                            Else
                                rank = "GPLE_D"
                            End If

                            updCmd.Parameters(0).Value = rank
                            updCmd.Parameters(1).Value = dest
                            updCmd.ExecuteNonQuery()
                        End While

                        updCmd.Dispose()
                    End Using
                End Using

                cn.Close()
            End Using
        Catch ex As Exception
            MsgBox("T400_ランク付け: ランク更新エラー: " & ex.Message)
            Return
        End Try

        ' ===== 5. T350_計算対象 の GPLEランク 列に T360_全出荷E集計 のランクを反映 =====
        ' GPLEランク 列が未存在の場合は追加
        Try
            Using cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")
                cn.Open()
                Try
                    Using addCmd As New OleDbCommand(
                        "ALTER TABLE [T350_計算対象] ADD COLUMN [GPLEランク] TEXT(10)", cn)
                        addCmd.ExecuteNonQuery()
                    End Using
                Catch
                    ' 既存の場合は無視
                End Try
            End Using
        Catch
        End Try

        MySQL = "UPDATE [T350_計算対象] " &
                "INNER JOIN [T360_全出荷E集計] ON [T350_計算対象].出荷先 = [T360_全出荷E集計].出荷先 " &
                "SET [T350_計算対象].[GPLEランク] = [T360_全出荷E集計].[GPLEランク];"
        SQL実行(MySQL)

    End Sub

    Public Sub T370_Iランク付け()

        ' ===== 1. T370* テーブルを削除 =====
        DEL_table("T370*")

        ' ===== 2. T370_全出荷I集計 を アイテム × GPL合計 で作成 =====
        MySQL = "SELECT アイテム, Sum(GPL) AS GPL合計 INTO [T370_全出荷I集計] " &
                "FROM T350_計算対象 " &
                "GROUP BY アイテム"
        SQL実行(MySQL)

        ' ===== 3. GPLIランク 列を追加 =====
        Try
            Using cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")
                cn.Open()
                Using addCmd As New OleDbCommand(
                    "ALTER TABLE [T370_全出荷I集計] ADD COLUMN [GPLIランク] TEXT(10)", cn)
                    addCmd.ExecuteNonQuery()
                End Using
            End Using
        Catch
            ' 列が既に存在する場合は無視
        End Try

        ' ===== 4. GPL合計 を降順に読み込み累積比率でランク付け =====
        Dim connStr As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";"

        ' 4-1. GPL 全合計を取得
        Dim totalGPL As Double = 0
        Try
            Using cn As New OleDbConnection(connStr)
                cn.Open()
                Using cmd As New OleDbCommand(
                    "SELECT Sum(GPL合計) FROM [T370_全出荷I集計]", cn)
                    Dim result As Object = cmd.ExecuteScalar()
                    If result IsNot Nothing AndAlso Not IsDBNull(result) Then
                        totalGPL = Convert.ToDouble(result)
                    End If
                End Using
            End Using
        Catch ex As Exception
            MsgBox("T370_Iランク付け: GPL合計取得エラー: " & ex.Message)
            Return
        End Try

        If totalGPL = 0 Then
            MsgBox("T370_Iランク付け: T370_全出荷I集計 の GPL合計が 0 です。処理を中止します。")
            Return
        End If

        ' 4-2. ランク閾値（累積比率 %）を定義
        EIQ_A1ランク = 50 : EIQ_A2ランク = 20 : EIQ_Bランク = 15 : EIQ_Cランク = 10 : EIQ_Dランク = 5
        Dim th_A1 As Double = EIQ_A1ランク                                           ' 50
        Dim th_A2 As Double = EIQ_A1ランク + EIQ_A2ランク                            ' 70
        Dim th_B As Double = EIQ_A1ランク + EIQ_A2ランク + EIQ_Bランク              ' 85
        Dim th_C As Double = EIQ_A1ランク + EIQ_A2ランク + EIQ_Bランク + EIQ_Cランク ' 95
        Dim th_D As Double = 100 ' 残り全て

        ' 4-3. GPL合計 降順で読み込みながら累積比率を計算してランクを UPDATE
        Try
            Using cn As New OleDbConnection(connStr)
                cn.Open()

                Dim 累積GPL As Double = 0

                Using selCmd As New OleDbCommand(
                    "SELECT アイテム, GPL合計 FROM [T370_全出荷I集計] ORDER BY GPL合計 DESC", cn)
                    Using rdr As OleDbDataReader = selCmd.ExecuteReader()

                        Dim updCmd As New OleDbCommand(
                            "UPDATE [T370_全出荷I集計] SET [GPLIランク] = ? WHERE [アイテム] = ?", cn)
                        updCmd.Parameters.Add(New OleDbParameter("?", OleDbType.VarChar, 10))
                        updCmd.Parameters.Add(New OleDbParameter("?", OleDbType.VarChar, 20))

                        While rdr.Read()
                            Dim item As String = rdr("アイテム").ToString()
                            Dim gpl As Double = If(IsDBNull(rdr("GPL合計")), 0, Convert.ToDouble(rdr("GPL合計")))

                            累積GPL += gpl
                            Dim 累積比率 As Double = (累積GPL / totalGPL) * 100.0

                            Dim rank As String
                            If 累積比率 <= th_A1 Then
                                rank = "GPLI_A1"
                            ElseIf 累積比率 <= th_A2 Then
                                rank = "GPLI_A2"
                            ElseIf 累積比率 <= th_B Then
                                rank = "GPLI_B"
                            ElseIf 累積比率 <= th_C Then
                                rank = "GPLI_C"
                            Else
                                rank = "GPLI_D"
                            End If

                            updCmd.Parameters(0).Value = rank
                            updCmd.Parameters(1).Value = item
                            updCmd.ExecuteNonQuery()
                        End While

                        updCmd.Dispose()
                    End Using
                End Using

                cn.Close()
            End Using
        Catch ex As Exception
            MsgBox("T370_Iランク付け: ランク更新エラー: " & ex.Message)
            Return
        End Try

        ' ===== 5. T350_計算対象 の GPLIランク 列に T370_全出荷I集計 のランクを反映 =====
        ' GPLIランク 列が未存在の場合は追加
        Try
            Using cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";")
                cn.Open()
                Try
                    Using addCmd As New OleDbCommand(
                        "ALTER TABLE [T350_計算対象] ADD COLUMN [GPLIランク] TEXT(10)", cn)
                        addCmd.ExecuteNonQuery()
                    End Using
                Catch
                    ' 既存の場合は無視
                End Try
            End Using
        Catch
        End Try

        MySQL = "UPDATE [T350_計算対象] " &
                "INNER JOIN [T370_全出荷I集計] ON [T350_計算対象].アイテム = [T370_全出荷I集計].アイテム " &
                "SET [T350_計算対象].[GPLIランク] = [T370_全出荷I集計].[GPLIランク];"
        SQL実行(MySQL)

    End Sub

    Public Sub T400_ランク集計()
        'T350_計算対象 を 進行連番/GPLEランク/GPLIランク ごとに集計
        MySQL = "SELECT T350_計算対象." & 進行連番 & ", T350_計算対象.GPLEランク, T350_計算対象.GPLIランク, Count(T350_計算対象.行連番) AS 行数, Sum(T350_計算対象.G行) AS 出庫回数, Sum(T350_計算対象.Gバ) AS バラ数, Sum(T350_計算対象.Gケ) AS ケース数, Sum(T350_計算対象.GPL) AS PL数, Sum(T350_計算対象.G容) AS 容積, Sum(T350_計算対象.G重) AS 重量 FROM T350_計算対象 GROUP BY T350_計算対象.進行連番, T350_計算対象.GPLEランク, T350_計算対象.GPLIランク;"
        SQL実行(MySQL)

        '2. T370_全出荷I集計 を GPLIランク ごとに アイテム数 を集計
        MySQL = "SELECT T370_全出荷I集計.GPLIランク, Count(T370_全出荷I集計.[アイテム]) AS アイテム数 FROM T370_全出荷I集計 GROUP BY T370_全出荷I集計.GPLIランク;"
        SQL実行(MySQL)

        '3. T350_計算対象 から行数・バラ数を集計
        MySQL = "SELECT Count(T350_計算対象.行連番) AS 行数, Sum(T350_計算対象.Gバ) AS バラ数 FROM T350_計算対象;"
        SQL実行(MySQL)

        '4. T350_計算対象 を GPLEランク/GPLIランク ごとに集計

        MySQL = "SELECT
                    T350_計算対象.GPLEランク,
                    T350_計算対象.GPLIランク,
                    Count(T350_計算対象.行連番) AS 行数,
                    Sum(T350_計算対象.G行) AS 出庫回数,
                    Sum(T350_計算対象.Gバ) AS Gバ,
                    Sum(T350_計算対象.Gケ) AS Gケ,
                    Sum(T350_計算対象.GPL) AS GPL,
                    Sum(T350_計算対象.G容) AS G容,
                    Sum(T350_計算対象.G重) AS G重
                INTO
                    T400_ランク集計
                FROM
                    T350_計算対象
                GROUP BY
                    T350_計算対象.GPLEランク,
                    T350_計算対象.GPLIランク;"
        SQL実行(MySQL)



    End Sub
    Public Sub T500_データモデル更新改()

    End Sub
    Public Sub T500_データモデル更新()

        Dim connStr As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";"

        ' T800_計算対象 から 進行連番 を取得
        Dim 進行連番 As Integer = 0
        Try
            Using cn As New OleDbConnection(connStr)
                cn.Open()
                Using cmd As New OleDbCommand("SELECT DISTINCT 進行連番 FROM T800_計算対象", cn)
                    Dim obj As Object = cmd.ExecuteScalar()
                    If obj IsNot Nothing AndAlso Not IsDBNull(obj) Then
                        進行連番 = Convert.ToInt32(obj)
                    End If
                End Using
            End Using
        Catch ex As Exception
            MsgBox("T500更新: 進行連番取得エラー: " & ex.Message)
            Return
        End Try
        If 進行連番 = 0 Then Return

        ' ランク名 → 列インデックス（1-5）
        Dim eRankMap As New Dictionary(Of String, Integer) From {
            {"GPLE_A1", 1}, {"GPLE_A2", 2}, {"GPLE_B", 3}, {"GPLE_C", 4}, {"GPLE_D", 5}
        }
        Dim iRankMap As New Dictionary(Of String, Integer) From {
            {"GPLI_A1", 1}, {"GPLI_A2", 2}, {"GPLI_B", 3}, {"GPLI_C", 4}, {"GPLI_D", 5}
        }

        ' 集計値格納配列
        Dim eCount(5) As Double
        Dim iCount(5) As Double
        Dim 行数M(25) As Double
        Dim バラ数M(25) As Double
        Dim ケースM(25) As Double
        Dim PLM(25) As Double
        Dim 容積M(25) As Double
        Dim 重量M(25) As Double
        Dim 出荷先数 As Double = 0
        Dim アイテム数 As Double = 0
        Dim 総行数 As Double = 0
        Dim 総バラ数 As Double = 0

        ' ===== データ取得 =====
        Try
            Using cn As New OleDbConnection(connStr)
                cn.Open()

                Using cmd As New OleDbCommand("SELECT Count(*) FROM [T360_全出荷E集計]", cn)
                    Dim r As Object = cmd.ExecuteScalar()
                    If r IsNot Nothing AndAlso Not IsDBNull(r) Then 出荷先数 = Convert.ToDouble(r)
                End Using

                Using cmd As New OleDbCommand("SELECT Count(*) FROM [T370_全出荷I集計]", cn)
                    Dim r As Object = cmd.ExecuteScalar()
                    If r IsNot Nothing AndAlso Not IsDBNull(r) Then アイテム数 = Convert.ToDouble(r)
                End Using

                Using cmd As New OleDbCommand("SELECT Count(行連番), Sum(Gバ) FROM [T800_計算対象]", cn)
                    Using rdr As OleDbDataReader = cmd.ExecuteReader()
                        If rdr.Read() Then
                            If Not IsDBNull(rdr(0)) Then 総行数 = Convert.ToDouble(rdr(0))
                            If Not IsDBNull(rdr(1)) Then 総バラ数 = Convert.ToDouble(rdr(1))
                        End If
                    End Using
                End Using

                Using cmd As New OleDbCommand(
                    "SELECT GPLEランク, Count(出荷先) FROM [T360_全出荷E集計] GROUP BY GPLEランク", cn)
                    Using rdr As OleDbDataReader = cmd.ExecuteReader()
                        While rdr.Read()
                            Dim rnk As String = rdr(0).ToString()
                            Dim cnt As Double = If(IsDBNull(rdr(1)), 0, Convert.ToDouble(rdr(1)))
                            If eRankMap.ContainsKey(rnk) Then eCount(eRankMap(rnk)) = cnt
                        End While
                    End Using
                End Using

                Using cmd As New OleDbCommand(
                    "SELECT GPLIランク, Count(アイテム) FROM [T370_全出荷I集計] GROUP BY GPLIランク", cn)
                    Using rdr As OleDbDataReader = cmd.ExecuteReader()
                        While rdr.Read()
                            Dim rnk As String = rdr(0).ToString()
                            Dim cnt As Double = If(IsDBNull(rdr(1)), 0, Convert.ToDouble(rdr(1)))
                            If iRankMap.ContainsKey(rnk) Then iCount(iRankMap(rnk)) = cnt
                        End While
                    End Using
                End Using

                Using cmd As New OleDbCommand(
                    "SELECT GPLEランク, GPLIランク, " &
                    "Count(行連番) AS 行数, Sum(G行) AS 出庫回数, Sum(Gバ) AS バラ数, " &
                    "Sum(Gケ) AS ケース数, Sum(GPL) AS PL数, Sum(G容) AS 容積, Sum(G重) AS 重量 " &
                    "FROM [T800_計算対象] GROUP BY GPLEランク, GPLIランク", cn)
                    Using rdr As OleDbDataReader = cmd.ExecuteReader()
                        While rdr.Read()
                            Dim eRnk As String = If(IsDBNull(rdr("GPLEランク")), "", rdr("GPLEランク").ToString())
                            Dim iRnk As String = If(IsDBNull(rdr("GPLIランク")), "", rdr("GPLIランク").ToString())
                            If Not (eRankMap.ContainsKey(eRnk) AndAlso iRankMap.ContainsKey(iRnk)) Then Continue While
                            Dim idx As Integer = (eRankMap(eRnk) - 1) * 5 + iRankMap(iRnk)
                            行数M(idx) = If(IsDBNull(rdr("行数")), 0, Convert.ToDouble(rdr("行数")))
                            バラ数M(idx) = If(IsDBNull(rdr("バラ数")), 0, Convert.ToDouble(rdr("バラ数")))
                            ケースM(idx) = If(IsDBNull(rdr("ケース数")), 0, Convert.ToDouble(rdr("ケース数")))
                            PLM(idx) = If(IsDBNull(rdr("PL数")), 0, Convert.ToDouble(rdr("PL数")))
                            容積M(idx) = If(IsDBNull(rdr("容積")), 0, Convert.ToDouble(rdr("容積")))
                            重量M(idx) = If(IsDBNull(rdr("重量")), 0, Convert.ToDouble(rdr("重量")))
                        End While
                    End Using
                End Using

                cn.Close()
            End Using
        Catch ex As Exception
            MsgBox("T500更新: データ取得エラー: " & ex.Message)
            Return
        End Try

        ' ===== UPDATE を分割して実行（フィールド数上限回避） =====
        Dim whr As String = " WHERE [モデル連番]=" & 進行連番

        Try
            ' --- (1) 基本集計 + E1-E5 + I1-I5 ---
            MySQL = "UPDATE [T500_データモデル] SET " &
                    "出荷先数=" & 出荷先数 & ", アイテム数=" & アイテム数 & ", " &
                    "バラ数量=" & 総バラ数 & ", 行数=" & 総行数 & ", " &
                    "E1=" & eCount(1) & ", E2=" & eCount(2) & ", E3=" & eCount(3) & ", E4=" & eCount(4) & ", E5=" & eCount(5) & ", " &
                    "I1=" & iCount(1) & ", I2=" & iCount(2) & ", I3=" & iCount(3) & ", I4=" & iCount(4) & ", I5=" & iCount(5) &
                    whr
            SQL実行(MySQL)

            ' --- (2) 行数01-25 ---
            Dim sb As New System.Text.StringBuilder()
            sb.Append("UPDATE [T500_データモデル] SET ")
            For idx As Integer = 1 To 25
                If idx > 1 Then sb.Append(", ")
                sb.Append("行数" & idx.ToString("00") & "=" & 行数M(idx))
            Next
            sb.Append(whr)
            SQL実行(sb.ToString())

            ' --- (3) バラ数01-25 ---
            sb.Clear()
            sb.Append("UPDATE [T500_データモデル] SET ")
            For idx As Integer = 1 To 25
                If idx > 1 Then sb.Append(", ")
                sb.Append("バラ数" & idx.ToString("00") & "=" & バラ数M(idx))
            Next
            sb.Append(whr)
            SQL実行(sb.ToString())

            ' --- (4) ケース01-25 ---
            sb.Clear()
            sb.Append("UPDATE [T500_データモデル] SET ")
            For idx As Integer = 1 To 25
                If idx > 1 Then sb.Append(", ")
                sb.Append("ケース" & idx.ToString("00") & "=" & ケースM(idx))
            Next
            sb.Append(whr)
            SQL実行(sb.ToString())

            ' --- (5) PL01-25 ---
            sb.Clear()
            sb.Append("UPDATE [T500_データモデル] SET ")
            For idx As Integer = 1 To 25
                If idx > 1 Then sb.Append(", ")
                sb.Append("PL" & idx.ToString("00") & "=" & PLM(idx))
            Next
            sb.Append(whr)
            SQL実行(sb.ToString())

            ' --- (6) 容積01-25 ---
            sb.Clear()
            sb.Append("UPDATE [T500_データモデル] SET ")
            For idx As Integer = 1 To 25
                If idx > 1 Then sb.Append(", ")
                sb.Append("容積" & idx.ToString("00") & "=" & 容積M(idx))
            Next
            sb.Append(whr)
            SQL実行(sb.ToString())

            ' --- (7) 重量01-25 ---
            sb.Clear()
            sb.Append("UPDATE [T500_データモデル] SET ")
            For idx As Integer = 1 To 25
                If idx > 1 Then sb.Append(", ")
                sb.Append("重量" & idx.ToString("00") & "=" & 重量M(idx))
            Next
            sb.Append(whr)
            SQL実行(sb.ToString())

        Catch ex As Exception
            MsgBox("T500更新: UPDATE エラー: " & ex.Message)
        End Try

    End Sub

    ''' <summary>
    ''' T400_ランク集計 の結果（1.-4.）を元に T500_データモデル を更新します。
    ''' モデル連番（進行連番）をキーに、E/I ランク別集計・5×5マトリクスを書き込みます。
    ''' UPDATE文を分割して「定義されているフィールドが多すぎる」エラーを回避します。
    ''' </summary>
    Public Sub T500_データモデル更新1()

        Dim connStr As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MyDB & ";"

        ' T350_計算対象 から 進行連番 を取得
        Dim 進行連番 As Integer = 0
        Try
            Using cn As New OleDbConnection(connStr)
                cn.Open()
                Using cmd As New OleDbCommand("SELECT DISTINCT 進行連番 FROM T350_計算対象", cn)
                    Dim obj As Object = cmd.ExecuteScalar()
                    If obj IsNot Nothing AndAlso Not IsDBNull(obj) Then
                        進行連番 = Convert.ToInt32(obj)
                    End If
                End Using
            End Using
        Catch ex As Exception
            MsgBox("T500更新: 進行連番取得エラー: " & ex.Message)
            Return
        End Try
        If 進行連番 = 0 Then Return

        ' ランク名 → 列インデックス（1-5）
        Dim eRankMap As New Dictionary(Of String, Integer) From {
            {"GPLE_A1", 1}, {"GPLE_A2", 2}, {"GPLE_B", 3}, {"GPLE_C", 4}, {"GPLE_D", 5}
        }
        Dim iRankMap As New Dictionary(Of String, Integer) From {
            {"GPLI_A1", 1}, {"GPLI_A2", 2}, {"GPLI_B", 3}, {"GPLI_C", 4}, {"GPLI_D", 5}
        }

        ' 集計値格納配列
        Dim eCount(5) As Double
        Dim iCount(5) As Double
        Dim 行数M(25) As Double
        Dim バラ数M(25) As Double
        Dim ケースM(25) As Double
        Dim PLM(25) As Double
        Dim 容積M(25) As Double
        Dim 重量M(25) As Double
        Dim 出荷先数 As Double = 0
        Dim アイテム数 As Double = 0
        Dim 総行数 As Double = 0
        Dim 総バラ数 As Double = 0

        ' ===== データ取得 =====
        Try
            Using cn As New OleDbConnection(connStr)
                cn.Open()

                Using cmd As New OleDbCommand("SELECT Count(*) FROM [T360_全出荷E集計]", cn)
                    Dim r As Object = cmd.ExecuteScalar()
                    If r IsNot Nothing AndAlso Not IsDBNull(r) Then 出荷先数 = Convert.ToDouble(r)
                End Using

                Using cmd As New OleDbCommand("SELECT Count(*) FROM [T370_全出荷I集計]", cn)
                    Dim r As Object = cmd.ExecuteScalar()
                    If r IsNot Nothing AndAlso Not IsDBNull(r) Then アイテム数 = Convert.ToDouble(r)
                End Using

                Using cmd As New OleDbCommand("SELECT Count(行連番), Sum(Gバ) FROM [T350_計算対象]", cn)
                    Using rdr As OleDbDataReader = cmd.ExecuteReader()
                        If rdr.Read() Then
                            If Not IsDBNull(rdr(0)) Then 総行数 = Convert.ToDouble(rdr(0))
                            If Not IsDBNull(rdr(1)) Then 総バラ数 = Convert.ToDouble(rdr(1))
                        End If
                    End Using
                End Using

                Using cmd As New OleDbCommand(
                    "SELECT GPLEランク, Count(出荷先) FROM [T360_全出荷E集計] GROUP BY GPLEランク", cn)
                    Using rdr As OleDbDataReader = cmd.ExecuteReader()
                        While rdr.Read()
                            Dim rnk As String = rdr(0).ToString()
                            Dim cnt As Double = If(IsDBNull(rdr(1)), 0, Convert.ToDouble(rdr(1)))
                            If eRankMap.ContainsKey(rnk) Then eCount(eRankMap(rnk)) = cnt
                        End While
                    End Using
                End Using

                Using cmd As New OleDbCommand(
                    "SELECT GPLIランク, Count(アイテム) FROM [T370_全出荷I集計] GROUP BY GPLIランク", cn)
                    Using rdr As OleDbDataReader = cmd.ExecuteReader()
                        While rdr.Read()
                            Dim rnk As String = rdr(0).ToString()
                            Dim cnt As Double = If(IsDBNull(rdr(1)), 0, Convert.ToDouble(rdr(1)))
                            If iRankMap.ContainsKey(rnk) Then iCount(iRankMap(rnk)) = cnt
                        End While
                    End Using
                End Using

                Using cmd As New OleDbCommand(
                    "SELECT GPLEランク, GPLIランク, " &
                    "Count(行連番) AS 行数, Sum(G行) AS 出庫回数, Sum(Gバ) AS バラ数, " &
                    "Sum(Gケ) AS ケース数, Sum(GPL) AS PL数, Sum(G容) AS 容積, Sum(G重) AS 重量 " &
                    "FROM [T350_計算対象] GROUP BY GPLEランク, GPLIランク", cn)
                    Using rdr As OleDbDataReader = cmd.ExecuteReader()
                        While rdr.Read()
                            Dim eRnk As String = If(IsDBNull(rdr("GPLEランク")), "", rdr("GPLEランク").ToString())
                            Dim iRnk As String = If(IsDBNull(rdr("GPLIランク")), "", rdr("GPLIランク").ToString())
                            If Not (eRankMap.ContainsKey(eRnk) AndAlso iRankMap.ContainsKey(iRnk)) Then Continue While
                            Dim idx As Integer = (eRankMap(eRnk) - 1) * 5 + iRankMap(iRnk)
                            行数M(idx) = If(IsDBNull(rdr("行数")), 0, Convert.ToDouble(rdr("行数")))
                            バラ数M(idx) = If(IsDBNull(rdr("バラ数")), 0, Convert.ToDouble(rdr("バラ数")))
                            ケースM(idx) = If(IsDBNull(rdr("ケース数")), 0, Convert.ToDouble(rdr("ケース数")))
                            PLM(idx) = If(IsDBNull(rdr("PL数")), 0, Convert.ToDouble(rdr("PL数")))
                            容積M(idx) = If(IsDBNull(rdr("容積")), 0, Convert.ToDouble(rdr("容積")))
                            重量M(idx) = If(IsDBNull(rdr("重量")), 0, Convert.ToDouble(rdr("重量")))
                        End While
                    End Using
                End Using

                cn.Close()
            End Using
        Catch ex As Exception
            MsgBox("T500更新: データ取得エラー: " & ex.Message)
            Return
        End Try

        ' ===== UPDATE を分割して実行（フィールド数上限回避） =====
        Dim whr As String = " WHERE [モデル連番]=" & 進行連番

        Try
            ' --- (1) 基本集計 + E1-E5 + I1-I5 ---
            MySQL = "UPDATE [T500_データモデル] SET " &
                    "出荷先数=" & 出荷先数 & ", アイテム数=" & アイテム数 & ", " &
                    "バラ数量=" & 総バラ数 & ", 行数=" & 総行数 & ", " &
                    "E1=" & eCount(1) & ", E2=" & eCount(2) & ", E3=" & eCount(3) & ", E4=" & eCount(4) & ", E5=" & eCount(5) & ", " &
                    "I1=" & iCount(1) & ", I2=" & iCount(2) & ", I3=" & iCount(3) & ", I4=" & iCount(4) & ", I5=" & iCount(5) &
                    whr
            SQL実行(MySQL)

            ' --- (2) 行数01-25 ---
            Dim sb As New System.Text.StringBuilder()
            sb.Append("UPDATE [T500_データモデル] SET ")
            For idx As Integer = 1 To 25
                If idx > 1 Then sb.Append(", ")
                sb.Append("行数" & idx.ToString("00") & "=" & 行数M(idx))
            Next
            sb.Append(whr)
            SQL実行(sb.ToString())

            ' --- (3) バラ数01-25 ---
            sb.Clear()
            sb.Append("UPDATE [T500_データモデル] SET ")
            For idx As Integer = 1 To 25
                If idx > 1 Then sb.Append(", ")
                sb.Append("バラ数" & idx.ToString("00") & "=" & バラ数M(idx))
            Next
            sb.Append(whr)
            SQL実行(sb.ToString())

            ' --- (4) ケース01-25 ---
            sb.Clear()
            sb.Append("UPDATE [T500_データモデル] SET ")
            For idx As Integer = 1 To 25
                If idx > 1 Then sb.Append(", ")
                sb.Append("ケース" & idx.ToString("00") & "=" & ケースM(idx))
            Next
            sb.Append(whr)
            SQL実行(sb.ToString())

            ' --- (5) PL01-25 ---
            sb.Clear()
            sb.Append("UPDATE [T500_データモデル] SET ")
            For idx As Integer = 1 To 25
                If idx > 1 Then sb.Append(", ")
                sb.Append("PL" & idx.ToString("00") & "=" & PLM(idx))
            Next
            sb.Append(whr)
            SQL実行(sb.ToString())

            ' --- (6) 容積01-25 ---
            sb.Clear()
            sb.Append("UPDATE [T500_データモデル] SET ")
            For idx As Integer = 1 To 25
                If idx > 1 Then sb.Append(", ")
                sb.Append("容積" & idx.ToString("00") & "=" & 容積M(idx))
            Next
            sb.Append(whr)
            SQL実行(sb.ToString())

            ' --- (7) 重量01-25 ---
            sb.Clear()
            sb.Append("UPDATE [T500_データモデル] SET ")
            For idx As Integer = 1 To 25
                If idx > 1 Then sb.Append(", ")
                sb.Append("重量" & idx.ToString("00") & "=" & 重量M(idx))
            Next
            sb.Append(whr)
            SQL実行(sb.ToString())

        Catch ex As Exception
            MsgBox("T500更新: UPDATE エラー: " & ex.Message)
        End Try

    End Sub
End Module